/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.mvc.models
{
	import com.puny.mvc.MvcEvent;
	import com.puny.mvc.helpers.DelayHelper;
	import com.puny.utils.PetriNet;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	public class CommaSeparatedVariable extends EventDispatcher
	{
		[Embed(source="csvParser.xml", mimeType="application/octet-stream")]
		private var CONFIG:Class;
		
		private var _loader:URLLoader;
		private var _net:PetriNet;
		private var _csv:String;
		private var _pos:Number=0;
		private var _current:String;
		private var _delimiter:String;
		private var _quotation:String;
		private var _escapeChar:String;
		private var _newLineChar:String;
		private var _line:Array;
		private var _lines:Array;
		private var _column:String;
		private var _stack:Number;
		private var _last:int;
		public function CommaSeparatedVariable(fileName:String)
		{
			_delimiter = ",";
			_quotation = "\"";
			_escapeChar = "\\";
			_newLineChar = "\n";
			_stack = 40;
			
			_loader = new URLLoader();
			_loader.addEventListener(Event.COMPLETE, loadedHandler);

			_loader.load(new URLRequest(fileName));
			_net = new PetriNet(new XML(new CONFIG()));
			_net.addPlaceListeners("charReady", takeCharHandler);
			_net.addPlaceListeners("takenChar", takenCharHandler);
			_net.addPlaceListeners("charReady2", takeCharHandler);
			_net.addPlaceListeners("normalChar", normalCharHandler);
			
			super();
		}
						
		private function normalCharHandler(event:Event):void {
			_net.transit("addCharToColumn");
		}
		
		private function loadedHandler(event:Event):void {
			_csv = event.currentTarget.data as String;
			_pos = 0;
			_line = new Array();
			_lines = new Array();
			_column = "";
			_net.transit("start");
		}
		
		private function takeCharHandler(event:Event):void {
			if (_pos == _csv.length) {
				updateLines();
				dispatchEvent(new MvcEvent(MvcEvent.READY));
				return;
			}
			_current = _csv.charAt(_pos);
			_pos++;
			if (_pos % _stack == 0) {
				DelayHelper.setup(0, null, takeChar);
			} else {
				takeChar();
			}
		}
		
		private function takeChar():void {
			_net.transit("takeChar");
			_net.transit("takeChar2");
		}
		
		private function takenCharHandler(event:Event):void {
			var fnc:Function;
			if (_current == _delimiter && _net.canFire("finishColumn")) {
				updateLine();
				fnc = finishColumn;
			} else if (_current == _quotation && (_net.canFire("enterQuot") || _net.canFire("exitQuot"))) {
				fnc = handleQuotation;
			} else if (_current == _escapeChar && _net.canFire("escape")) {
				fnc = escape;
			} else if (_current == _newLineChar && _net.canFire("newLine")) {
				updateLines();
				_line = new Array();
				fnc = newLine;
			} else {
				_column = _column.concat(_current);
				fnc = normal;
			}
			if (fnc != null) {
				fnc();
			}
		}
		
		private function finishColumn():void {
			_net.transit("finishColumn");
		}
		
		private function handleQuotation():void {
			_net.transit("enterQuot");
			_net.transit("exitQuot");
		}
		
		private function escape():void {
			_net.transit("escape");
		}
		
		private function newLine():void {
			_net.transit("newLine");
		}
		
		private function normal():void {
			_net.transit("others");
		}
		
		private function updateLine():void {
			_line.push(_column);
			_column = "";
		}
		
		private function updateLines():void {
			updateLine();
			_lines.push(_line);
		}

		/**
		 * default = ","; 
		 * @param value
		 * 
		 */
		public function set delimiter(value:String):void
		{
			_delimiter = value;
		}

		/**
		 * default = "\""; 
		 * @param value
		 * 
		 */
		public function set quotation(value:String):void
		{
			_quotation = value;
		}

		/**
		 * default = "\\"; 
		 * @param value
		 * 
		 */
		public function set escapeChar(value:String):void
		{
			_escapeChar = value;
		}

		/**
		 * default = "\n"; 
		 * @param value
		 * 
		 */
		public function set newLineChar(value:String):void
		{
			_newLineChar = value;
		}

		/**
		 * default = 40; 
		 * @param value
		 * 
		 */
		public function set stack(value:Number):void
		{
			_stack = value;
		}

		public function get lines():Array
		{
			return _lines;
		}
		
		public function valueAt(col:int, row:int):String {
			return _lines[row][col];
		}
	}
}